package com.laxcen.facesdk;

import androidx.fragment.app.FragmentActivity;

import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Size;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.laxcen.facesdk.facelib.bean.ImageData;
import com.laxcen.facesdk.facelib.core.AndroidConfig;
import com.laxcen.facesdk.facelib.core.FaceCheckManager;
import com.laxcen.facesdk.facelib.core.model.FaceLandmarkInfo;
import com.laxcen.facesdk.facelib.engine.ActionEngine;
import com.laxcen.facesdk.facelib.engine.CameraEngine;
import com.laxcen.facesdk.facelib.engine.Const;
import com.laxcen.facesdk.facelib.view.CircleImageView;
import com.laxcen.facesdk.facelib.view.LegacyCameraConnectionFragment;
import com.laxcen.facesdk.facelib.view.OverlayView;
import com.laxcen.facesdk.facelib.encoder.EncoderBus;
import com.laxcen.facesdk.facelib.engine.CheckFaceEngine;
import com.laxcen.facesdk.facelib.utils.MyLogger;
import com.laxcen.facesdk.facelib.utils.NV21ToBitmap;
import com.laxcen.facesdk.facelib.utils.PermissionUtils;
import com.laxcen.facesdk.facelib.utils.SensorEventUtil;

import java.util.List;

public class MainActivity  extends FragmentActivity implements
        Camera.PreviewCallback, View.OnClickListener {
    private static final String TAG = "CameraActicity";
    // 照相机预览宽
    public int previewWidth = 0;
    // 照相机预览高
    public int previewHeight = 0;
    // 展示区域宽
    public static float ScreenWidth;
    // 展示区域高
    public static float ScreenHeight;
    public static int CameraId = 0;
    private boolean isProcessingFrame = false;
    // 是否是前置摄像头
    public static boolean is_front_camera = Const.IS_FRONT_CAMERA;
    private Handler handler;
    private HandlerThread handlerThread;
    protected SensorEventUtil sensorEventUtil;
    // 相机的数据 nv21格式
    protected byte[] mNV21Bytes;
    private Runnable postInferenceCallback;
    private Runnable imageConverter;
    public NV21ToBitmap nv21ToBitmap;
    private ActionEngine actionEngine;

    /*****操作按钮****/
    private ImageView btn_back;//返回
    private TextView pre_toast_text;//提示信息
    private CircleImageView detect_reg_image_item;//通过活体检测
    private Button by_living_detection_btn;//重新检测
    private CircleImageView no_detect_reg_image_item;//未通过活体检测
    private Button failed_in_vivo_testBtn;//重新检测

    private RelativeLayout pay_hintRl;
    private View finance_failed_in_vivo_test;
    private View finance_by_living_detection;;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_main);
        toCheckPermission();
    }
    private void toCheckPermission(){
        PermissionUtils.checkPermission(this, () -> init());
    }
    @Override
    public void onRequestPermissionsResult(final int requestCode, final String[] permissions, final int[] grantResults) {
        if (requestCode == 1) {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED
                    && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                init();
            } else {
                toCheckPermission();
            }
        }
    }
    private void init(){
        btn_back = findViewById(R.id.btn_back);
        pre_toast_text = findViewById(R.id.pre_toast_text);
        detect_reg_image_item = findViewById(R.id.detect_reg_image_item);
        by_living_detection_btn = findViewById(R.id.by_living_detection_btn);
        no_detect_reg_image_item = findViewById(R.id.no_detect_reg_image_item);
        failed_in_vivo_testBtn = findViewById(R.id.failed_in_vivo_testBtn);
        pay_hintRl = findViewById(R.id.pay_hintRl);
        finance_failed_in_vivo_test = findViewById(R.id.finance_failed_in_vivo_test);
        finance_by_living_detection = findViewById(R.id.finance_by_living_detection);

        btn_back.setOnClickListener(this);
        by_living_detection_btn.setOnClickListener(this);
        failed_in_vivo_testBtn.setOnClickListener(this);

        //检测结果
        actionEngine = ActionEngine.getInstance();
        actionEngine.setOnActionCallback(new ActionEngine.OnActionCallback() {
            @Override
            public void onMessage(String msg) {
                pre_toast_text.setText(msg);
            }

            @Override
            public void onResult(boolean isOk, String msg) {
                pay_hintRl.setVisibility(View.VISIBLE);
                if(isOk){
                    detect_reg_image_item.setImageBitmap(bitmap);
                    finance_by_living_detection.setVisibility(View.VISIBLE);
                    finance_failed_in_vivo_test.setVisibility(View.GONE);
                }else{
                    no_detect_reg_image_item.setImageBitmap(bitmap);
                    finance_by_living_detection.setVisibility(View.GONE);
                    finance_failed_in_vivo_test.setVisibility(View.VISIBLE);
                }
            }
        });
        actionEngine.start();
        //动作识别监测
        CheckFaceEngine.getInstance().setOnFaceCheckResult(type -> {
            switch (type){
                case Const.ACTION_TYPE_EYE:
                case Const.ACTION_TYPE_MOUTH:
                case Const.ACTION_TYPE_LEFT_RIGHT_HEAD:
                case Const.ACTION_TYPE_RISE_HEAD:
                case Const.ACTION_TYPE_BOW_HEAD:
                    actionEngine.onResult(type);
                    break;
                case Const.ACTION_TYPE_NOT_ZHENGDUI:
                   pre_toast_text.setText("请正对屏幕!");
                    break;
                case Const.ACTION_TYPE_NO_FACE:
                    pre_toast_text.setText("保持面部在取景框内");
                    break;
                default:
                    if(bitmap==null) {
                        toGetImage();
                    }
                    break;
            }
        });
        nv21ToBitmap = new NV21ToBitmap( MainActivity.this);
        setFragment();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_back:
                finish();
                break;
            case R.id.by_living_detection_btn:
            case R.id.failed_in_vivo_testBtn:
                bitmap = null;
                pay_hintRl.setVisibility(View.GONE);
                finance_by_living_detection.setVisibility(View.GONE);
                finance_failed_in_vivo_test.setVisibility(View.GONE);
                actionEngine.start();
                break;
        }
    }

    public void faceinit() {
        mNV21Bytes = new byte[previewHeight * previewWidth];
        /**
         * 初始化
         * */
        FaceCheckManager.init(
                MainActivity.this,
                AndroidConfig
                        .create()
                        .setCameraMode()
                        .setDefaultFunc().openFunc(AndroidConfig.Func.Attribution)
                        .setDefaultInputImageFormat()
                        .setInputImageSize(previewWidth, previewHeight)
                        .setOutputImageSize((int) ScreenWidth, (int) ScreenHeight)
        );
        if (sensorEventUtil == null) {
            sensorEventUtil = new SensorEventUtil(this);
        }
    }
    @SuppressLint("NewApi")
    @Override
    public void onPreviewFrame(final byte[] bytes, final Camera camera) {
        if (isProcessingFrame) {
            return;
        }
        isProcessingFrame = true;
        try {
            if (mNV21Bytes == null) {
                Camera.Size previewSize = camera.getParameters().getPreviewSize();
                previewHeight = previewSize.height;
                previewWidth = previewSize.width;
                faceinit();
                EncoderBus.GetInstance().onSetFrameConfiguration(previewHeight, previewWidth);
                trackingOverlay = findViewById(R.id.facing_overlay);
                trackingOverlay.addCallback(canvas -> EncoderBus.GetInstance().onDraw(canvas));
            }
        } catch (final Exception e) {
            MyLogger.logError(TAG, "onPreviewFrame: " + e);
            return;
        }
        imageConverter = () -> mNV21Bytes = bytes;
        postInferenceCallback = () -> {
            camera.addCallbackBuffer(bytes);
            isProcessingFrame = false;
        };
        processImage();
    }

    @Override
    public synchronized void onStart() {
        super.onStart();
    }

    @Override
    public synchronized void onResume() {
        super.onResume();
        handlerThread = new HandlerThread("inference");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
        processImage();
    }

    @Override
    public synchronized void onPause() {
        handlerThread.quitSafely();
        try {
            handlerThread.join();
            handlerThread = null;
            handler = null;
        } catch (final InterruptedException e) {
            MyLogger.logError(TAG, "onPause: " + e);
        }
        super.onPause();
    }

    @Override
    public synchronized void onStop() {
        super.onStop();
    }

    @Override
    public synchronized void onDestroy() {
        super.onDestroy();
        /**
         * 释放
         * */
        FaceCheckManager.release();
        actionEngine.destory();
        thread = null;
    }
    protected void setFragment() {
        LegacyCameraConnectionFragment fragment = new LegacyCameraConnectionFragment(this,
                getLayoutId(), new Size(720, 720));
        CameraId = fragment.getCameraId();
        getFragmentManager().beginTransaction().replace(R.id.container, fragment).commit();
    }
    protected void readyForNextImage() {
        if (postInferenceCallback != null) {
            postInferenceCallback.run();
        }
    }

    protected synchronized void runInBackground(final Runnable r) {
        if (handler != null) {
            handler.post(r);
        }
    }

    //得到最新的bytes
    protected void getCameraBytes() {
        if (imageConverter != null) {
            imageConverter.run();
        }
    }
    protected int getLayoutId() {
        return R.layout.camera_connection_fragment;
    }
    private OverlayView trackingOverlay;
    protected void processImage() {
        if (sensorEventUtil!= null) {
            getCameraBytes();
            int degree = CameraEngine.getInstance().getCameraOrientation(sensorEventUtil.orientation);
            /**
             * 设置旋转角
             */
            FaceCheckManager.Camera.setRotation(degree - 90, false, (int) MainActivity.ScreenWidth, (int) MainActivity.ScreenHeight);

            /**
             * 获取人脸信息
             */
            FaceCheckManager.FaceDetect faceDetect = FaceCheckManager.detect(mNV21Bytes);
            if (faceDetect.getFaceCount() > 0) {
                List<FaceLandmarkInfo> landmarkInfos = faceDetect.landmark2d();
                CheckFaceEngine.getInstance().onCheckAction(landmarkInfos);
            }else {
                CheckFaceEngine.getInstance().noFace();
            }
        }
        runInBackground(() -> {
            readyForNextImage();
            if (trackingOverlay!=null) {
                trackingOverlay.postInvalidate();
            }
        });
    }

    /**
     *  获取人脸截图
     */
    private boolean isStart = true;
    private Thread thread;
    private void toGetImage(){
        if(bitmap!=null){
            return;
        }
        if(!isStart){
            return;
        }
        isStart = false;
        thread = new Thread(() -> {
            try {
                    Bitmap bitmap = nv21ToBitmap.nv21ToBitmap(mNV21Bytes,previewWidth,previewHeight);
                    ImageData imageData = new ImageData();
                    imageData.setBitmap(bitmap);
                    Message message = new Message();
                    message.what=1;
                    message.obj = imageData;
                    handler2.sendMessage(message);
            }catch (Exception e){
                e.printStackTrace();
            }
            isStart = true;
        });
        thread.start();
    }

    private Bitmap bitmap;
    private Handler handler2 = new Handler() {
        @Override
        public void handleMessage(Message message) {
            super.handleMessage(message);
            switch (message.what) {
                case 1:
                    ImageData imageData = (ImageData)message.obj;
                    bitmap = imageData.getBitmap();
                    break;
            }
        }
    };

}